﻿#include "Graph2DWindowBase.h"
#include "Curve2DPlotor.h"
#include "TextFileParser.h"
#include "DataManager/WindowTotalData.h"

namespace
{
    void NormalizeAndLog(QVector<double>& vec, bool isNor, bool isLog, bool isPower = false)
    {
        if (vec.isEmpty() || (!isNor && !isLog))
        {
            return;
        }

        if (isNor && !isLog)
        {
            auto max_iter = std::max_element(vec.begin(), vec.end(),
                [](double a, double b) {
                    return std::abs(a) < std::abs(b);
                });
            double max_value = std::abs(*max_iter); // 绝对值的最大值
            for (auto& i : vec)
            {
                i /= max_value;
            }
            return;
        }
        int coefficient = 20;
        if (isPower)
        {
            coefficient = 10;
        }
        if (!isNor && isLog)
        {
            for (auto& i : vec)
            {
                i = coefficient * std::log10(i);
            }
            return;
        }
        if (isNor && isLog) // 先归一化再取对数
        {
            auto max_iter = std::max_element(vec.begin(), vec.end(),
                [](double a, double b) {
                    return std::abs(a) < std::abs(b);
                });
            double max_value = std::abs(*max_iter); // 绝对值的最大值

            for (auto& i : vec)
            {
                i = coefficient * std::log10(i / max_value);
            }
        }
    }
} // namespace

namespace pst
{
    Graph2DWindowBase::Graph2DWindowBase(QWidget* parent) : QWidget(parent)
    {
        m_colorList << QColor{255, 0, 0}
                    << QColor{0, 255, 0}
                    //<< QColor{ 0,0,255 }
                    << QColor{128, 158, 173}
                    << QColor{0, 128, 0}
                    << QColor{127, 255, 0}
                    << QColor{153, 50, 204}
                    << QColor{255, 140, 0}
                    << QColor{155, 93, 112}
                    << QColor{240, 128, 128}
                    << QColor{255, 69, 0}
                    << QColor{0, 111, 255}
                    << QColor{0, 0, 128}
                    << QColor{255, 0, 255}
                    << QColor{128, 0, 128};

        m_customPlot = new Curve2DPlotor(this);
        m_customPlot->legend->setVisible(true);
        m_customPlot->legend->blockSignals(true);
        m_customPlot->setAntialiasedElements(QCP::aeAll);

        initConnections();

        slot_legendTitleFontFamilyChanged("宋体");
        slot_legendTitleFontSizeChanged(20);
        InitializeResultWindowStyle();
    }

    Graph2DWindowBase::~Graph2DWindowBase()
    {
        if (m_customPlot)
        {
            delete m_customPlot;
            m_customPlot = nullptr;
        }
    }

    void Graph2DWindowBase::addGraph2D(Info2DPointer& info1)
    {
        qDebug() << "void Graph2DWindowBase::addGraph2D(Info2DPointer& info1)";
    }

    bool Graph2DWindowBase::saveScreenShot(const QString& path)
    {
        //获取后缀
        QString suffix = QFileInfo(path).suffix();
        if (suffix.toUpper() == "JPG")
        {
            return m_customPlot->saveJpg(path, 0, 0, 2.0, -1, 96);
        }
        if(suffix.toUpper() == "PNG")
        {
            return m_customPlot->savePng(path, 0, 0, 2.0, -1, 96);
        }
        return false;
    }

    Info2DPointer Graph2DWindowBase::getInfoFromItem(QStandardItem* item) const
    {
        return Info2DPointer();
    }

    void Graph2DWindowBase::slot_adaptiveRange()
    {
        m_customPlot->rescaleAxes(true);
        m_customPlot->replot();
    }

    void Graph2DWindowBase::slot_amplify()
    {
        double factor = qPow(0.85, 1);
        if (m_customPlot->xAxis != nullptr)
        {
            m_customPlot->xAxis->scaleRange(factor);
        }
        if (m_customPlot->yAxis != nullptr)
        {
            m_customPlot->yAxis->scaleRange(factor);
        }
        m_customPlot->replot();
    }

    void Graph2DWindowBase::slot_minification()
    {
        double factor = qPow(0.85, -1);
        if (m_customPlot->xAxis != nullptr)
        {
            m_customPlot->xAxis->scaleRange(factor);
        }
        if (m_customPlot->yAxis != nullptr)
        {
            m_customPlot->yAxis->scaleRange(factor);
        }
        m_customPlot->replot();
    }

    // 设置框中选中的曲线发生改变->根据曲线信息更新m_settings
    void Graph2DWindowBase::slot_chosenItemsChanged(const QList<QStandardItem*>& itemList)
    {
        qDebug() << "void Graph2DWindowBase::slot_chosenItemsChanged(const QList<QStandardItem*>& itemList)";
    }

    void Graph2DWindowBase::slot_updateCurveData(
        const QList<int> selectedCurveInfoIDList,
        const int changedInfoID, const QVector<int>& otherKeyIndex)
    {    
        for (const auto& i : selectedCurveInfoIDList)
        {
            auto dataInfo = WindowTotalDataInstance->getInfomationCurve2DBasicalByID(i);
            //Info2DPointer dataInfo = nullptr;
            //bool _isExist = false;
            //for (auto _curvePair : m_curveMap)
            //{
            //    if (_curvePair.first == i)
            //    {
            //        dataInfo = _curvePair.second;
            //        _isExist = true;
            //        break;
            //    }
            //}
            //if (!_isExist)
            //{
            //    // todo 警告
            //    continue;
            //}

            //if (!judgmentItemInfoPairIsExist(i))
            //{
            //    // todo 警告
            //    continue;
            //}

            //auto& dataInfo = m_curveMap[i];
            auto changedInfo = WindowTotalDataInstance->getInfomationCurve2DBasicalByID(changedInfoID);
            if (!changedInfo->getIsMuti()) // 单选，更新固定值和value
            {
                if (!otherKeyIndex.isEmpty())
                {
                    QVector<double> otherKeyData;
                    auto textFileparser = dataInfo->getReader();
                    QVector<QVector<double>> keyList = textFileparser->getEachColDataOfKey();
                    int index = 0;
                    for (int i = 0; i < keyList.size(); ++i)
                    {
                        if (i != dataInfo->getScanParameterIndex() && i != dataInfo->getSecondScanParameterIndex())
                        {
                            otherKeyData.append(keyList.at(i).at(otherKeyIndex.at(index)));
                            ++index;
                        }
                    }
                    dataInfo->setOtherKeyData(otherKeyData);
                }
                else
                {
                    dataInfo->setOtherKeyData(changedInfo->getOtherKeyData());
                }
                dataInfo->setValueIndex(changedInfo->getValueIndex());
                dataInfo->setValueComponent(changedInfo->getValueComponent());
                dataInfo->enableMathematicalOperations(changedInfo->getIsMathematicalOperations());
                dataInfo->setCalculationFormula(changedInfo->getCalculationFormula());
                dataInfo->setIsDBState(changedInfo->getIsDBState());
                dataInfo->setIsDB(changedInfo->getIsDB());
            }
            dataInfo->setIsNormalized(changedInfo->getIsNormalized());
            auto _info = WindowTotalDataInstance->getInfomationCurve2DBasicalByID(i);
            this->updateCurve(_info->getSidebarItem(), dataInfo); // 更新而非新建
        }
    }

    void Graph2DWindowBase::slot_legendTitleFontFamilyChanged(const QString& fontFamily)
    {

        auto font = m_customPlot->legend->font();
        font.setFamily(fontFamily);
        m_customPlot->legend->setFont(font);
        m_customPlot->replot();
    }

    void Graph2DWindowBase::slot_legendTitleFontSizeChanged(int fontSize)
    {
        auto font = m_customPlot->legend->font();
        font.setPointSizeF(fontSize);
        m_customPlot->legend->setFont(font);
        m_customPlot->replot();
    }

    void Graph2DWindowBase::InitializeResultWindowStyle()
    {
        auto basePenX = m_customPlot->xAxis->basePen();
        basePenX.setWidthF(1);
        m_customPlot->xAxis->setBasePen(basePenX);
        auto selectBasePenX = m_customPlot->xAxis->selectedBasePen();
        selectBasePenX.setWidthF(2);
        m_customPlot->xAxis->setSelectedBasePen(selectBasePenX);

        auto tickLabelFontX = m_customPlot->xAxis->tickLabelFont();
        tickLabelFontX.setPointSize(16);
        m_customPlot->xAxis->setTickLabelFont(tickLabelFontX);
        auto selectTickLabelFontX = m_customPlot->xAxis->selectedTickLabelFont();
        selectTickLabelFontX.setPointSize(16);
        m_customPlot->xAxis->setSelectedTickLabelFont(selectTickLabelFontX);

        auto basePenY = m_customPlot->yAxis->basePen();
        basePenY.setWidthF(1);
        m_customPlot->yAxis->setBasePen(basePenY);
        auto selectBasePenY = m_customPlot->yAxis->selectedBasePen();
        selectBasePenY.setWidthF(2);
        m_customPlot->yAxis->setSelectedBasePen(selectBasePenY);

        auto tickLabelFontY = m_customPlot->yAxis->tickLabelFont();
        tickLabelFontY.setPointSize(16);
        m_customPlot->yAxis->setTickLabelFont(tickLabelFontY);
        auto selectTickLabelFontY = m_customPlot->yAxis->selectedTickLabelFont();
        selectTickLabelFontY.setPointSize(16);
        m_customPlot->yAxis->setSelectedTickLabelFont(selectTickLabelFontY);

        auto penGrid = m_customPlot->xAxis->grid()->pen();
        penGrid.setWidthF(1);
        m_customPlot->xAxis->grid()->setPen(penGrid);
        m_customPlot->yAxis->grid()->setPen(penGrid);

        auto subGridPen = m_customPlot->xAxis->grid()->subGridPen();
        subGridPen.setWidthF(1);
        m_customPlot->xAxis->grid()->setSubGridPen(subGridPen);
        m_customPlot->yAxis->grid()->setSubGridPen(subGridPen);

        auto title = qobject_cast<QCPTextElement*>(m_customPlot->plotLayout()->element(0, 0));
        if (title != nullptr)
        {
            auto fontTitle = title->font();
            fontTitle.setPointSize(20);
            title->setFont(fontTitle);
            title->setSelectedFont(fontTitle);
        }

        // legend
        auto fontLegend = m_customPlot->legend->font();
        fontLegend.setPointSize(16);
        m_customPlot->legend->setFont(fontLegend);
        m_customPlot->legend->setSelectedFont(fontLegend);
        auto borderPen = m_customPlot->legend->borderPen();
        borderPen.setWidthF(1);
        m_customPlot->legend->setBorderPen(borderPen);
        auto selectBorderPen = m_customPlot->legend->selectedBorderPen();
        selectBorderPen.setWidthF(1);
        m_customPlot->legend->setSelectedBorderPen(selectBorderPen);
    }

    void Graph2DWindowBase::initConnections()
    {
        qDebug() << "Graph2DWindowBase::initConnections()";
    }

    void Graph2DWindowBase::updateCurve(QStandardItem* item, Info2DPointer& info)
    {
        qDebug() << "Graph2DWindowBase::updateCurve(QStandardItem* item, Info2DPointer& info)";
    }

    void Graph2DWindowBase::normalizeAndLog(QVector<double>& vec, bool isNor, bool isLog, bool isPower)
    {
        NormalizeAndLog(vec, isNor, isLog, isPower);
    }

    void Graph2DWindowBase::slot_generateANewGraphCurve(const QList<QStandardItem*>& itemList,
                                                        const Info2DPointer& changedInfo)
    {
        QList<Info2DPointer> newDataList;

        for (const auto& i : itemList)
        {
            Info2DPointer dataInfo = nullptr;
            bool _isExist = false;
            for (auto _curvePair : m_curveMap)
            {
                if (_curvePair.first == i)
                {
                    dataInfo = _curvePair.second;
                    _isExist = true;
                    break;
                }
            }
            if (!_isExist)
            {
                // todo 警告
                continue;
            }
            //if (!itemList.contains(i))
            //{
            //    // todo 警告
            //    continue;
            //}
            //const auto& dataInfo = m_curveMap[i];
            auto _graph = dataInfo->getGraph();
            auto _reader = dataInfo->getReader();
            auto* curveAdd = dataInfo->getCurveLineAddress();

            if (curveAdd == nullptr || _graph == nullptr || _reader == nullptr)
            {
                // TODO 警告
                return;
            }

            auto changedScanName = changedInfo->getScanParameterName();
            auto keyNames = _reader->getEachColNameOfKey();
            auto newScanIndex = keyNames.indexOf(changedScanName);
            auto oldScanIndex = dataInfo->getScanParameterIndex();
            auto keyDataList = _reader->getEachColDataOfKey();
            // 设置新的扫描参数
            if (newScanIndex == -1)
            {
                // TODO 警告
                return;
            }
            // dataInfo->setScanParameterIndex(newScanIndex);

            // 设置新的otherKeyList
            QVector<double> otherKeyVector = dataInfo->getOtherKeyData();
            otherKeyVector.insert(oldScanIndex, keyDataList[oldScanIndex][0]);
            otherKeyVector.removeAt(newScanIndex);

            _reader->setScanParameterIndex(newScanIndex);

            QVector<QVector<double>> tempOtherKey;
            for (auto i : otherKeyVector)
            {
                tempOtherKey.append(QVector<double>{i});
            }
            _reader->setOtherKeyParameter(tempOtherKey);
            QList<Info2DPointer> newYList;
            QPair<int, int> tem{dataInfo->getValueIndex(), dataInfo->getValueComponent()};

            _reader->getChosenLinesFromKey(QList<QPair<int, int>>{tem}, newYList);

            for (auto& i : newYList)
            {
                i->setGraphType(dataInfo->getGraphType());
                i->setDataSources(dataInfo->getDataSources());
                newDataList.append(i);
            }
        }

        emit signal_generateANewGraphCurve(newDataList);
    }

    void Graph2DWindowBase::addCurveItemInfoPair(QStandardItem* item, Info2DPointer& info)
    {
        bool _isExist = false;
        for (auto& _curvePair : m_curveMap)
        {
            if (_curvePair.first == item)
            {
                _curvePair.second = info;
                _isExist = true;
                break;
            }
        }
        if (!_isExist)
        {
            m_curveMap.append(QPair<QStandardItem*, Info2DPointer>(item, info));
        }
    }
    Info2DPointer Graph2DWindowBase::getCurveInfoByItem(QStandardItem* item) const
    {
        for (auto _curvePair : m_curveMap)
        {
            if (_curvePair.first == item)
            {
                return _curvePair.second;
            }
        }
        return nullptr;
    }
    QStandardItem* Graph2DWindowBase::getItemFromCurveInfo(Info2DPointer& info) const
    {
        for (auto _curvePair : m_curveMap)
        {
            if (_curvePair.second == info)
            {
                return _curvePair.first;
            }
        }
        return nullptr;
    }
    bool Graph2DWindowBase::judgmentItemInfoPairIsExist(QStandardItem* item) const
    {
        for (auto _curvePair : m_curveMap)
        {
            if (_curvePair.first == item)
            {
                return true;
            }
        }
        return false;
    }
    void Graph2DWindowBase::removeCurveItemInfoPair(QStandardItem* item)
    {
        for (auto _curvePair : m_curveMap)
        {
            if (_curvePair.first == item)
            {
                m_curveMap.removeOne(_curvePair);
                break;
            }
        }
    }
} // namespace pst
